﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using BizElements.TemplateEngine;

namespace BizElements.Generator
{
    public partial class SubcomponentListCtl : UserControl
    {
        ITemplateInputComponent parentComponent;
        ComponentType subcomponentType;
        List<InputComponentInfo> subcomponents = new List<InputComponentInfo>();
        IList<TemplateComponentVariableDefinition> componentVariableDefinitions = new List<TemplateComponentVariableDefinition>();
        IDictionary<string, IDictionary<string, string>> allComponentVariables = new Dictionary<string, IDictionary<string, string>>();

        public SubcomponentListCtl()
        {
            InitializeComponent();
        }

        private void SubcomponentListCtl_Load(object sender, EventArgs e)
        {
            RefreshSubcomponentList();
        }

        #region Events, getters and setters.

        public IDictionary<string, IDictionary<string, string>> GetAllComponentVariables()
        {
            return this.allComponentVariables;
        }

        public void SetComponentData(ITemplateInputComponent parentComponent, ComponentType subcomponentType, IEnumerable<ITemplate> allTemplates, IDictionary<string, IDictionary<string, string>> allComponentVariables)
        {
            this.parentComponent = parentComponent;
            this.subcomponentType = subcomponentType;
            this.componentVariableDefinitions = TemplateUtil.GetApplicableComponentVariablesForChildren(parentComponent, subcomponentType, allTemplates);
            this.allComponentVariables = allComponentVariables ?? new Dictionary<string, IDictionary<string, string>>();
        }

        #endregion

        private sealed class InputComponentInfo
        {
            public ITemplateInputComponent Component;
            public string Metadata;
        }

        #region Refresh.

        private void RefreshSubcomponentList()
        {
            this.uiSubcomponents.Items.Clear();
            this.subcomponents.Clear();
            if (this.parentComponent == null)
                return;

            var children = parentComponent.GetChildren(this.subcomponentType);
            foreach (ITemplateInputComponent childComponent in children)
                this.subcomponents.Add(new InputComponentInfo() { Component = childComponent, Metadata = "" });

            Rebind();
        }        

        private void Rebind()
        {
            this.uiSubcomponents.BeginUpdate();
            this.uiSubcomponents.Items.Clear();
            foreach (InputComponentInfo obj in this.subcomponents)
            {
                ListViewItem item = this.uiSubcomponents.Items.Add(obj.Component.Name);
                obj.Metadata = "";
                foreach (Pair<string, string> nameAndVal in GetComponentVariables(obj.Component.FullName))
                {
                    if (!string.IsNullOrEmpty(nameAndVal.Value))
                        obj.Metadata += string.Format("{0}={1};", nameAndVal.Name, nameAndVal.Value);
                }

                item.SubItems.Add(obj.Metadata);
            }

            this.uiSubcomponents.EndUpdate();
        }

        #endregion

        private void uiSubcomponents_DoubleClick(object sender, EventArgs e)
        {
            if (this.uiSubcomponents.FocusedItem == null)
                return;

            if (this.componentVariableDefinitions.Count == 0)
            {
                MessageBox.Show("No compatibile variables/parameters defined for displayed subcomponent in selected templates.");
                return;
            }

            // Slow double click may disable item.
            this.uiSubcomponents.FocusedItem.Checked = true;
            int idx = this.uiSubcomponents.FocusedItem.Index;
            if ((idx >= 0) && (idx < this.subcomponents.Count))
            {
                ComponentVariablesFrm varEditor = new ComponentVariablesFrm();
                ITemplateInputComponent component = this.subcomponents[idx].Component;
                List<Pair<string, string>> currentValues = GetComponentVariables(component.FullName);
                varEditor.SetComponentVariables(component.FullName, this.componentVariableDefinitions, currentValues);
                varEditor.VariablesChanged += new EventHandler<EventArgs<IEnumerable<Triple<string, string, string>>>>(varEditor_VariablesChanged);
                varEditor.ShowDialog();
            }
        }

        void varEditor_VariablesChanged(object sender, EventArgs<IEnumerable<Triple<string, string, string>>> e)
        {
            foreach (Triple<string, string, string> componentVariableAndValue in e.Item)
                SetComponentVariableValue(componentVariableAndValue.Key1, componentVariableAndValue.Key2, componentVariableAndValue.Value);

            Rebind();
        }

        private void SetComponentVariableValue(string componentName, string variableName, string variableValue)
        {
            if (string.IsNullOrEmpty(componentName) || string.IsNullOrEmpty(variableName))
                return;

            IDictionary<string, string> componentVariables;
            this.allComponentVariables.TryGetValue(componentName, out componentVariables);
            if (componentVariables == null)
            {
                componentVariables = new Dictionary<string, string>();
                this.allComponentVariables[componentName] = componentVariables;
            }

            componentVariables[variableName] = variableValue;
        }

        private List<Pair<string, string>> GetComponentVariables(string componentName)
        {
            List<Pair<string, string>> currentValues = new List<Pair<string, string>>();
            IDictionary<string, string> componentVariables;
            this.allComponentVariables.TryGetValue(componentName, out componentVariables);
            if (componentVariables == null)
                return currentValues;

            foreach (KeyValuePair<string, string> nameAndValue in componentVariables)
                currentValues.Add(new Pair<string, string>(nameAndValue.Key, nameAndValue.Value));

            return currentValues;
        }
    }
}
